package org.dromara.system.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.utils.BeanUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.api.model.LoginUser;
import org.dromara.system.constants.OrderConstants;
import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.config.ApiConfig;
import org.dromara.system.domain.vo.PayPolicyVo;
import org.dromara.system.domain.vo.PayTypeVo;
import org.dromara.system.kernel.PayGroupAccountKernel;
import org.dromara.system.mapper.*;
import org.dromara.system.service.IPayGroupAccountService;
import org.dromara.system.service.IPayOrderService;
import org.dromara.system.service.IPayTypeService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.PayAccountBo;
import org.dromara.system.domain.vo.PayAccountVo;
import org.dromara.system.service.IPayAccountService;

import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * 收款账号Service业务层处理
 *
 * @author Gavino
 * @date 2024-10-22
 */
@RequiredArgsConstructor
@Service
public class PayAccountServiceImpl implements IPayAccountService {

    private final PayAccountMapper baseMapper;
    private final PayGroupTypeMapper payGroupTypeMapper;
    private final PayGroupAccountMapper groupAccountMapper;
    private final SysUserMapper sysUserMapper;
    private final PayGroupAccountKernel payGroupAccountKernel;
    private final IPayTypeService payTypeService;
    private final IPayOrderService payOrderService;

    /**
     * 构建请求地址
     *
     * @param account 账号信息
     * @return 返回请求地址
     */
    @Override
    public String buildRequestUrl(PayAccount account) {
        try {
            //获取插件地址
            String plugin = account.getPlugin();

            //如果插件地址为空，则根据平台配置组装插件地址
            if (StringUtils.isEmpty(plugin)) {
                PayTypeVo payType = payTypeService.queryById(account.getPayTypeId());
                if (payType == null) {
                    return null;
                }
                JSONObject json = JSONObject.parseObject(StringUtils.removeComments(payType.getConfig()));
                List<ApiConfig> apiConfigs = json.getList("apiConfig", ApiConfig.class);

                //获取对应API类型的插件地址
                ApiConfig config = null;
                for (ApiConfig apiConfig : apiConfigs) {
                    if (Objects.equals(apiConfig.getValue(), account.getApiType())) {
                        config = apiConfig;
                        break;
                    }
                }
                if (config == null) {
                    return null;
                }
                plugin = config.getPlugin();
            }

            if (StringUtils.isEmpty(plugin)) {
                return null;
            }

            //请求地址
            return account.getFormatDomain() + (plugin.endsWith("/") ? plugin : plugin + "/");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 查询收款账号
     *
     * @param accountId 主键
     * @return 收款账号
     */
    @Override
    public PayAccount selectById(Long accountId) {
        PayAccount obj = RedisUtils.getCacheObject(OrderConstants.pay_account_cache + accountId);
        if (obj == null) {
            obj = baseMapper.selectById(accountId);
            if (obj != null) {
                RedisUtils.setCacheObject(OrderConstants.pay_account_cache + accountId, obj);
            }
        }
        return obj;
    }

    /**
     * 获取这个应用未绑定的收款账号
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 收款账号分页列表
     */
    @Override
    public TableDataInfo<PayAccountVo> noBindsList(PayAccountBo bo, PageQuery pageQuery) {

        PayGroupType groupType = payGroupTypeMapper.selectById(bo.getGroupTypeId());

        MPJLambdaWrapper<PayAccount> mpq = new MPJLambdaWrapper<>();
        mpq.leftJoin("pay_group_account t1 ON t.account_id = t1.account_id AND t1.group_id = " + bo.getGroupId() + " and t1.group_type_id = " + bo.getGroupTypeId());

        mpq.isNull("t1.account_id");
        mpq.eq(PayAccount::getPayTypeId, groupType.getTypeId());
        mpq.eq(PayAccount::getStatus, 1);
        if (!LoginHelper.isSuperAdmin()) {
            mpq.eq(PayAccount::getAgentId, LoginHelper.getUserId());
        }
        if (bo.getIsDelete() != null) {
            mpq.eq(PayAccount::getIsDelete, bo.getIsDelete());
        }
        mpq.selectAll(PayAccount.class);
        Page<PayAccountVo> result = baseMapper.selectJoinPage(pageQuery.build(), PayAccountVo.class, mpq);
        return TableDataInfo.build(result);
    }

    /**
     * 分页查询收款账号列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 收款账号分页列表
     */
    @Override
    public TableDataInfo<PayAccountVo> queryPageList(PayAccountBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PayAccount> lqw = buildQueryWrapper(bo);
        Page<PayAccountVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的收款账号列表
     *
     * @param bo 查询条件
     * @return 收款账号列表
     */
    @Override
    public List<PayAccountVo> queryList(PayAccountBo bo) {
        LambdaQueryWrapper<PayAccount> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PayAccount> buildQueryWrapper(PayAccountBo bo) {

        LambdaQueryWrapper<PayAccount> lqw = Wrappers.lambdaQuery();
        if (LoginHelper.isSupplier()) {
            bo.setSupplierId(LoginHelper.getUserId());
        }
        else if (LoginHelper.isService()) {
            String accountIds = LoginHelper.getLoginUser().getAccountIds();
            if (StringUtils.isNotBlank(accountIds)) {
                lqw.in(PayAccount::getAccountId, Arrays.asList(accountIds.split(",")));
            } else {
                lqw.eq(PayAccount::getAccountId, -1);
            }
        }
        else if (!LoginHelper.isSuperAdmin()) {
            bo.setAgentId(LoginHelper.getUserId());
        }

        lqw.like(StringUtils.isNotBlank(bo.getAccountName()), PayAccount::getAccountName, bo.getAccountName());
        lqw.eq(bo.getPayTypeId() != null, PayAccount::getPayTypeId, bo.getPayTypeId());
        lqw.like(StringUtils.isNotBlank(bo.getDomain()), PayAccount::getDomain, bo.getDomain());
        lqw.eq(StringUtils.isNotBlank(bo.getIp()), PayAccount::getIp, bo.getIp());
        lqw.eq(StringUtils.isNotBlank(bo.getPlugin()), PayAccount::getPlugin, bo.getPlugin());
        lqw.eq(bo.getStatus() != null, PayAccount::getStatus, bo.getStatus());
        lqw.eq(bo.getApiType() != null, PayAccount::getApiType, bo.getApiType());
        lqw.eq(bo.getGenerateOrder() != null, PayAccount::getGenerateOrder, bo.getGenerateOrder());
        lqw.eq(bo.getGenerateProduct() != null, PayAccount::getGenerateProduct, bo.getGenerateProduct());
        lqw.eq(StringUtils.isNotBlank(bo.getConfig()), PayAccount::getConfig, bo.getConfig());
        lqw.like(StringUtils.isNotBlank(bo.getRemark()), PayAccount::getRemark, bo.getRemark());
        lqw.eq(bo.getAgentId() != null, PayAccount::getAgentId, bo.getAgentId());
        lqw.eq(bo.getSupplierId() != null, PayAccount::getSupplierId, bo.getSupplierId());
        lqw.eq(bo.getIsDelete() != null, PayAccount::getIsDelete, bo.getIsDelete());
        return lqw;
    }

    /**
     * 新增收款账号
     *
     * @param bo 收款账号
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(PayAccountBo bo) {
        PayAccount add = MapstructUtils.convert(bo, PayAccount.class);
        validEntityBeforeSave(add);
        if (add.getStatus() == null) {
            add.setStatus(1);
        }

        if (LoginHelper.isSupplier()) {
            add.setSupplierId(LoginHelper.getUserId());
            add.setSupplierName(LoginHelper.getUsername());
            add.setAgentId(LoginHelper.getLoginUser().getAgentId());
            add.setAgentName(LoginHelper.getLoginUser().getAgentName());
        } else {
            if (add.getSupplierId() != null) {
                SysUser supplier = sysUserMapper.selectById(add.getSupplierId());
                add.setSupplierName(supplier.getUserName());
            }
            add.setAgentId(LoginHelper.getUserId());
            add.setAgentName(LoginHelper.getUsername());
        }
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
//            bo.setAccountId(add.getAccountId());
        }
        return flag;
    }

    /**
     * 修改收款账号
     *
     * @param bo 收款账号
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(PayAccountBo bo) {
        PayAccount update = MapstructUtils.convert(bo, PayAccount.class);
        validEntityBeforeSave(update);

        if (update.getSupplierId() != null) {
            SysUser supplier = sysUserMapper.selectById(update.getSupplierId());
            update.setSupplierName(supplier.getUserName());
        }

        update.setUpdateId(LoginHelper.getUserId());
        update.setUpdateName(LoginHelper.getUsername());

        LambdaQueryWrapper<PayAccount> query = new LambdaQueryWrapper<PayAccount>().eq(PayAccount::getAccountId, bo.getAccountId());
        if (LoginHelper.isAgent()) {
            query.eq(PayAccount::getAgentId, LoginHelper.getUserId());
        }
        if (LoginHelper.isSupplier()) {
            query.eq(PayAccount::getSupplierId, LoginHelper.getUserId());
        }
        PayAccount old = baseMapper.selectOne(query);


        boolean updateName = false;
        if (StringUtils.isNotBlank(bo.getAccountName())) {

            if (!Objects.equals(old.getAccountName(), bo.getAccountName())) {
                updateName = true;
            }
        }

        boolean tag = baseMapper.updateById(update) > 0;
        if (tag) {
            if(bo.getCountryType() == null) {
                bo.setCountryCode(null);
            }
            baseMapper.update(Wrappers.<PayAccount>lambdaUpdate().eq(PayAccount::getAccountId, bo.getAccountId()).set(PayAccount::getCountryType, bo.getCountryType()).set(PayAccount::getCountryCode, bo.getCountryCode()));

            if (Objects.equals(update.getStatus(), 2)) {
                //如果收款账号禁用,则同步更新轮询组的账号禁用
                PayGroupAccount up = new PayGroupAccount();
                up.setStatus(3);
                payGroupAccountKernel.updateGroupAccount(up, new LambdaQueryWrapper<PayGroupAccount>().eq(PayGroupAccount::getAccountId, update.getAccountId()));
            } else if (Objects.equals(update.getStatus(), 1)) {
                //如果收款账号禁用,则同步更新轮询组的账号禁用
                PayGroupAccount up = new PayGroupAccount();
                up.setStatus(2);
                payGroupAccountKernel.updateGroupAccount(up, new LambdaQueryWrapper<PayGroupAccount>().eq(PayGroupAccount::getAccountId, update.getAccountId()).eq(PayGroupAccount::getStatus, 3));
            }

            //更新订单账号名称
            if (updateName) {
                //如果收款账号名称发生变化,则同步更新订单账号名称
                LambdaUpdateWrapper<PayOrder> query1 = new LambdaUpdateWrapper<PayOrder>().eq(PayOrder::getAccountId, update.getAccountId());
                query1.set(PayOrder::getAccountName, update.getAccountName());
                CompletableFuture.runAsync(() -> payOrderService.updatePayOrder(query1));
            }
        }

        PayAccount obj = baseMapper.selectById(update.getAccountId());
        if (obj != null) {
            RedisUtils.setCacheObject(OrderConstants.pay_account_cache + obj.getAccountId(), obj);
        }
        return tag;
    }

    /**
     * 修改收款账号
     *
     * @param account 收款账号
     * @return 是否修改成功
     */
    @Override
    public Boolean updateById(PayAccount account) {
        boolean tag = baseMapper.updateById(account) > 0;

        if (tag) {
            PayAccount obj = baseMapper.selectById(account.getAccountId());
            if (obj != null) {
                RedisUtils.setCacheObject(OrderConstants.pay_account_cache + obj.getAccountId(), obj);
            }
        }
        return tag;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PayAccount entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除收款账号信息
     *
     * @param ids 待删除的主键集合
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Set<Long> ids, Integer isDelete) {

        LambdaUpdateWrapper<PayAccount> query = new LambdaUpdateWrapper<>();
        if (ids == null || ids.isEmpty()) {
            if (isDelete == 0) {
                //全部还原
                query.eq(PayAccount::getIsDelete, 1);
            } else {
                return false;
            }
        } else {
            query.in(PayAccount::getAccountId, ids);
        }

        if (LoginHelper.isAgent()) {
            query.eq(PayAccount::getAgentId, LoginHelper.getUserId());
        }
        if (LoginHelper.isSupplier()) {
            query.eq(PayAccount::getSupplierId, LoginHelper.getUserId());
        }

        List<PayAccount> list = baseMapper.selectList(query);
        for (PayAccount account : list) {
            RedisUtils.deleteObject(OrderConstants.pay_account_cache + account.getAccountId());
        }

        query.set(PayAccount::getIsDelete, isDelete);

        boolean tag = baseMapper.update(query) > 0;
        if (tag && isDelete == 1) {
            groupAccountMapper.update(new LambdaUpdateWrapper<PayGroupAccount>().in(PayGroupAccount::getAccountId, ids).set(PayGroupAccount::getStatus, 3));
        }

        return tag;
    }

    /**
     * 校验并批量删除收款账号信息
     *
     * @param ids 待删除的主键集合
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteByIds(Set<Long> ids) {

        LambdaQueryWrapper<PayAccount> query = new LambdaQueryWrapper<>();
        if (ids != null && !ids.isEmpty()) {
            query.in(PayAccount::getAccountId, ids);
        }

        if (LoginHelper.isAgent()) {
            query.eq(PayAccount::getAgentId, LoginHelper.getUserId());
        }

        query.eq(PayAccount::getIsDelete, 1);

        List<PayAccount> list = baseMapper.selectList(query);
        if (list == null || list.isEmpty()) {
            return true;
        }

        List<Long> accountIds = new ArrayList<>();
        for (PayAccount account : list) {
            accountIds.add(account.getAccountId());
            RedisUtils.deleteObject(OrderConstants.pay_account_cache + account.getAccountId());
        }

        groupAccountMapper.delete(new LambdaQueryWrapper<PayGroupAccount>().in(PayGroupAccount::getAccountId, accountIds));
        return baseMapper.delete(query) > 0;
    }
}
